Imports System.Xml.Serialization
Imports system.io
Imports System.Runtime.Serialization

Public Class CharactersInfo
    Private CharactersXmlFilename As String = "CharactersInfo.xml"
    Private ArmoryDataPath As String = "..\..\ArmoryData"
    Private DataPath As String = ""

    Private m_UpdateIntervalDays As Integer = 10    ' update if the data are older than this days value

    Private m_Region As String = "US"
    Private m_Realm As String = "Proudmoore"
    Private m_Filter As String = "[@level>='80']"

    Private ArmoryAccessCounter As Long = 0

    Public ItemDB As New ItemDB
    'Public EnchantDB As New EnchantDB

    Public Structure Characters
        <XmlAttribute()> Dim Region As String

        <XmlAttribute()> Dim Realm As String
        <XmlAttribute()> Dim Character As String
        <XmlAttribute()> Dim AkaChara As String
        <XmlAttribute()> Dim ClassName As String
        <XmlAttribute()> Dim Race As String
        <XmlAttribute()> Dim Gender As String
        <XmlAttribute()> Dim Guild As String
        <XmlAttribute()> Dim LastModified As String
        <XmlAttribute()> Dim Level As Integer
        <XmlAttribute()> Dim Achieve As Integer

        <XmlAttribute()> Dim Prof1name As String
        <XmlAttribute()> Dim Prof1value As Integer
        <XmlAttribute()> Dim Prof2name As String
        <XmlAttribute()> Dim Prof2value As Integer

        <XmlAttribute()> Dim Build1name As String
        <XmlAttribute()> Dim Build1 As Integer
        <XmlAttribute()> Dim Build2 As Integer
        <XmlAttribute()> Dim Build3 As Integer

        <XmlAttribute()> Dim Build2name As String
        <XmlAttribute()> Dim Build21 As Integer
        <XmlAttribute()> Dim Build22 As Integer
        <XmlAttribute()> Dim Build23 As Integer

        <XmlAttribute()> Dim Talent As String
        <XmlAttribute()> Dim Talent2 As String

        <XmlAttribute()> Dim Glyph() As Integer
        <XmlAttribute()> Dim Glyph2() As Integer

        <XmlAttribute()> Dim Health As Integer
        <XmlAttribute()> Dim Mana As Integer
        <XmlAttribute()> Dim Str As Integer
        <XmlAttribute()> Dim Sta As Integer
        <XmlAttribute()> Dim Agi As Integer
        <XmlAttribute()> Dim Int As Integer
        <XmlAttribute()> Dim Spi As Integer

        <XmlAttribute()> Dim SpellPower As Integer
        <XmlAttribute()> Dim HealPower As Integer
        <XmlAttribute()> Dim SpellHit As Integer
        <XmlAttribute()> Dim SpellCrit As Integer
        <XmlAttribute()> Dim SpellHaste As Integer
        <XmlAttribute()> Dim ManaRegRest As Single
        <XmlAttribute()> Dim ManaRegen As Single

        <XmlAttribute()> Dim MeleePower As Integer
        <XmlAttribute()> Dim MeleeDpsMH As Single
        <XmlAttribute()> Dim MeleeDpsOH As Single
        <XmlAttribute()> Dim MeleeWSpeedMH As Single
        <XmlAttribute()> Dim MeleeWSpeedOH As Single
        <XmlAttribute()> Dim MeleeHit As Integer
        <XmlAttribute()> Dim MeleeCrit As Integer
        <XmlAttribute()> Dim MeleeHasteMH As Integer
        <XmlAttribute()> Dim MeleeHasteOH As Integer
        <XmlAttribute()> Dim MeleePenet As Integer

        <XmlAttribute()> Dim RangedPower As Integer
        <XmlAttribute()> Dim RangedDps As Single
        <XmlAttribute()> Dim RangedWSpeed As Single
        <XmlAttribute()> Dim RangedHit As Integer
        <XmlAttribute()> Dim RangedCrit As Integer
        <XmlAttribute()> Dim RangedHaste As Integer
        <XmlAttribute()> Dim RangedPenet As Integer

        <XmlAttribute()> Dim Armor As Integer
        <XmlAttribute()> Dim Defense As Integer
        <XmlAttribute()> Dim Dodge As Integer
        <XmlAttribute()> Dim Parry As Integer
        <XmlAttribute()> Dim Block As Integer
        <XmlAttribute()> Dim Resilience As Single

        <XmlAttribute()> Dim iLvTotal As Integer
        <XmlAttribute()> Dim iLvAve As Single

        <XmlAttribute()> Dim items() As Integer
        <XmlAttribute()> Dim gems() As Integer
        <XmlAttribute()> Dim ench() As Integer

        <XmlAttribute()> Dim Achievements() As String

        <XmlAttribute()> Dim ErrCode As String
        <XmlAttribute()> Dim ErrCount As Integer
        <XmlAttribute()> Dim Rejected As Boolean
        '<XmlAttribute()> Dim NoChara As Boolean

        <XmlAttribute()> Dim LastUpdate As Date
    End Structure
    Public Shared CharacterData() As Characters

    Dim AccArmory As AccessArmory


#Region "Properties"

    Public ReadOnly Property Chara() As Characters()
        Get
            Return CharacterData
        End Get
    End Property

    Public Property Region() As String
        Get
            Return m_Region
        End Get
        Set(ByVal value As String)
            Dim armory As New WowCrawler.AccessArmory
            value = armory.GetRegionString(armory.GetRegionType(value))

            m_Region = value
        End Set
    End Property

    Public Property Realm() As String
        Get
            Return m_Realm
        End Get
        Set(ByVal value As String)
            m_Realm = value
        End Set
    End Property

    Public Property UpdateInterval() As Integer
        Get
            Return m_UpdateIntervalDays
        End Get
        Set(ByVal value As Integer)
            If value < -1 Then
                value = -1
            End If

            m_UpdateIntervalDays = value
        End Set
    End Property

    Public Property Filter() As String
        Get
            Return m_Filter
        End Get
        Set(ByVal value As String)
            m_Filter = value
        End Set
    End Property
#End Region


    Public Sub New()
        AccArmory = New AccessArmory
        If CharacterData Is Nothing Then

            NewCahracterData()

            DataPath = My.Computer.FileSystem.CombinePath(My.Computer.FileSystem.SpecialDirectories.AllUsersApplicationData, ArmoryDataPath)
            Try
                IO.Directory.CreateDirectory(DataPath)
            Catch ex As Exception
            End Try
            LoadArmoryData()
        End If
    End Sub

    Protected Overrides Sub Finalize()
        Dim compare As New CompareCharacters
        Array.Sort(CharacterData, compare)

        AccArmory = Nothing
        SaveArmoryData()

        MyBase.Finalize()
    End Sub

    Public Sub LoadArmoryData(Optional ByVal Filename As String = "")
        If Filename = "" Then
            Filename = My.Computer.FileSystem.CombinePath(DataPath, CharactersXmlFilename)
        End If

        Dim XU As New XmlUtils.AccessXml

        Try
            XU.ImportFromXml(CharacterData, Filename)
        Catch ex As Exception
        End Try

    End Sub

    Public Sub SaveArmoryData(Optional ByVal Filename As String = "")
        If Filename = "" Then
            Filename = My.Computer.FileSystem.CombinePath(DataPath, CharactersXmlFilename)
        End If

        Dim XU As New XmlUtils.AccessXml

        Try
            XU.ExportByXml(CharacterData, Filename)
        Catch ex As Exception

        End Try
    End Sub

    Private Function NewCahracterData() As Long
        Dim ct As Long = 0
        If CharacterData Is Nothing Then
            ct = 0
        Else
            ct = CharacterData.Length
        End If

        ReDim Preserve CharacterData(ct)
        CharacterData(ct) = New Characters

        CharacterData(ct).Region = ""

        CharacterData(ct).Realm = ""
        CharacterData(ct).Character = ""
        CharacterData(ct).ClassName = ""
        CharacterData(ct).Race = ""
        CharacterData(ct).Gender = ""
        CharacterData(ct).Guild = ""
        CharacterData(ct).LastModified = ""
        CharacterData(ct).Level = 0
        CharacterData(ct).Achieve = 0

        CharacterData(ct).Prof1name = ""
        CharacterData(ct).Prof1value = 0
        CharacterData(ct).Prof2name = ""
        CharacterData(ct).Prof2value = 0

        CharacterData(ct).Build1name = ""
        CharacterData(ct).Build1 = 0
        CharacterData(ct).Build2 = 0
        CharacterData(ct).Build3 = 0
        CharacterData(ct).Talent = ""

        CharacterData(ct).Build2name = ""

        CharacterData(ct).Health = 0
        CharacterData(ct).Mana = 0
        CharacterData(ct).Str = 0
        CharacterData(ct).Agi = 0
        CharacterData(ct).Sta = 0
        CharacterData(ct).Int = 0
        CharacterData(ct).Spi = 0

        CharacterData(ct).SpellPower = 0
        CharacterData(ct).SpellHit = 0
        CharacterData(ct).SpellCrit = 0
        CharacterData(ct).SpellHaste = 0

        CharacterData(ct).HealPower = 0
        CharacterData(ct).ManaRegRest = 0
        CharacterData(ct).ManaRegen = 0

        CharacterData(ct).MeleePower = 0
        CharacterData(ct).MeleeHit = 0
        CharacterData(ct).MeleeCrit = 0

        CharacterData(ct).RangedPower = 0
        CharacterData(ct).RangedHit = 0
        CharacterData(ct).RangedCrit = 0

        CharacterData(ct).Armor = 0
        CharacterData(ct).Defense = 0
        CharacterData(ct).Dodge = 0
        CharacterData(ct).Parry = 0
        CharacterData(ct).Block = 0
        CharacterData(ct).Resilience = 0

        CharacterData(ct).ErrCode = ""
        CharacterData(ct).ErrCount = 0
        'CharacterData(ct).NoChara = False

        CharacterData(ct).LastUpdate = Now()

        Return ct
    End Function

    Public Sub GetGuildMembersInfo(ByVal Guild As String, Optional ByVal Realm As String = "", Optional ByVal Region As String = "")
        If Region = "" Then
            Region = m_Region
        End If

        If Realm = "" Then
            Realm = m_Realm
        End If

        Dim Armory As New AccessArmory
        Dim XmlGuild As New Xml.XmlDocument
        Dim GuildNode As Xml.XmlElement = Nothing

        Armory.Region = Armory.GetRegionType(Region)

        Try
            GuildNode = Armory.GetArmoryGuildInfo(Realm, Guild, XmlGuild)
        Catch ex As Exception
        End Try
        Try
            XmlGuild.Save(My.Computer.FileSystem.CombinePath(DataPath, "LastArmoryGuildInfo.xml"))
        Catch ex As Exception
        End Try

        Dim ch As CharactersInfo.Characters
        If GuildNode IsNot Nothing Then
            Dim chara As Xml.XmlElement

            For Each chara In GuildNode.SelectNodes("character" & m_Filter)
                Try
                    ch = GetCharactersInfo(chara.Attributes("name").Value, Realm, Region)
                    ch.Guild = Guild
                    ch.ErrCount = 0
                Catch ex As Exception
                End Try
            Next
        End If
    End Sub

    Public Function GetCharactersInfo(ByVal Character As String, Optional ByVal Realm As String = "", Optional ByVal Region As String = "") As CharactersInfo.Characters
        If Character = "" Then
            Return Nothing
        End If

        If Region = "" Then
            Region = m_Region
        End If

        If Realm = "" Then
            Realm = m_Realm
        End If

        If CharacterData IsNot Nothing Then
            Dim i As Integer

            For i = 0 To CharacterData.Length - 1
                If LCase(CharacterData(i).Realm) = LCase(Realm) And LCase(CharacterData(i).Character) = LCase(Character) And CharacterData(i).Region = Region Then
                    'If ((Now - CharacterData(i).LastUpdate).Days < m_UpdateIntervalDays) And (CharacterData(i).Race <> "") Then
                    If (Now - CharacterData(i).LastUpdate).Days < m_UpdateIntervalDays Then
                        If CharacterData(i).Rejected And CharacterData(i).AkaChara <> "" Then
                            Return GetCharactersInfo(CharacterData(i).AkaChara, CharacterData(i).Realm, CharacterData(i).Region)
                        Else
                            Return CharacterData(i)
                        End If
                    Else
                        Return GetCharacterFromArmory(i)
                    End If
                End If
            Next

            For i = 0 To CharacterData.Length - 1
                If CharacterData(i).Realm = "" And CharacterData(i).Character = "" Then
                    CharacterData(i).Realm = Realm
                    CharacterData(i).Character = Character
                    CharacterData(i).Region = Region

                    Return GetCharacterFromArmory(i)
                End If
            Next
        End If

        Dim ct As Integer = NewCahracterData()
        CharacterData(ct).Character = Character
        CharacterData(ct).Realm = Realm
        CharacterData(ct).Region = Region

        Return GetCharacterFromArmory(ct)
    End Function

    Private Function GetCharacterFromArmory(ByVal CIndex As Integer) As CharactersInfo.Characters
        If Left(CharacterData(CIndex).Guild, 1) = "(" Then CharacterData(CIndex).Guild = ""
        If CharacterData(CIndex).Rejected Then
            If CharacterData(CIndex).AkaChara = "" Then
                Return CharacterData(CIndex)
            Else
                Return GetCharactersInfo(CharacterData(CIndex).AkaChara, CharacterData(CIndex).Realm, CharacterData(CIndex).Region)
            End If
        End If

        Dim Armory As New AccessArmory
        Dim XMLdoc As New Xml.XmlDocument
        Dim XMLnode As Xml.XmlElement

        Dim regCode As AccessArmory.RegionType = Armory.GetRegionType(CharacterData(CIndex).Region)

        Dim child As Xml.XmlElement

        Dim AchDB As New AchievementDB

        '===== character sheet =====
        Try
            XMLnode = Armory.GetArmoryCharacter(CharacterData(CIndex).Realm, CharacterData(CIndex).Character, XMLdoc, AccessArmory.UrlCharactersInfo.UrlCharacterSheet)
        Catch ex As Exception
            Return CharacterData(CIndex)
        End Try

        If XMLnode Is Nothing Then
            Return CharacterData(CIndex)
        End If

        CharacterData(CIndex).LastUpdate = Now()
        CharacterData(CIndex).ErrCode = ""
        Try
            CharacterData(CIndex).ErrCode = XMLnode.Attributes("errCode").Value
            'If XMLnode.Attributes("errCode").Value = "noCharacter" Then
            '    CharacterData(CIndex).NoChara = True
            '    Return CharacterData(CIndex)
            'End If
        Catch ex As Exception
        End Try
        If CharacterData(CIndex).ErrCode = "" Then
            CharacterData(CIndex).ErrCount = 0
        Else
            CharacterData(CIndex).ErrCount += 1
            If CharacterData(CIndex).ErrCount >= 5 Then
                'CharacterData(CIndex).Guild = "(Renamed or Transfered)"
            End If
            Return CharacterData(CIndex)
        End If


        '--- general info
        Try
            CharacterData(CIndex).Character = XMLnode.SelectSingleNode("character").Attributes("name").Value
            CharacterData(CIndex).ClassName = XMLnode.SelectSingleNode("character").Attributes("class").Value
            CharacterData(CIndex).Race = XMLnode.SelectSingleNode("character").Attributes("race").Value
            CharacterData(CIndex).Gender = XMLnode.SelectSingleNode("character").Attributes("gender").Value
            CharacterData(CIndex).Level = XMLnode.SelectSingleNode("character").Attributes("level").Value
            CharacterData(CIndex).Achieve = XMLnode.SelectSingleNode("character").Attributes("points").Value
            CharacterData(CIndex).LastModified = XMLnode.SelectSingleNode("character").Attributes("lastModified").Value
            CharacterData(CIndex).Guild = XMLnode.SelectSingleNode("character").Attributes("guildName").Value
        Catch ex As Exception
        End Try
        Try
            If XMLnode.SelectSingleNode("character").Attributes("name") IsNot Nothing And XMLnode.SelectSingleNode("character").Attributes("guildName") Is Nothing Then
                CharacterData(CIndex).Guild = ""
            End If
        Catch ex As Exception
        End Try

        '--- build 
        Try
            For Each child In XMLnode.SelectNodes("characterTab/talentSpecs/talentSpec")
                If child.Attributes("active") Is Nothing Then
                    CharacterData(CIndex).Build2name = child.Attributes("prim").Value
                    CharacterData(CIndex).Build21 = child.Attributes("treeOne").Value
                    CharacterData(CIndex).Build22 = child.Attributes("treeTwo").Value
                    CharacterData(CIndex).Build23 = child.Attributes("treeThree").Value
                ElseIf child.Attributes("active").Value = 0 Then
                    CharacterData(CIndex).Build2name = child.Attributes("prim").Value
                    CharacterData(CIndex).Build21 = child.Attributes("treeOne").Value
                    CharacterData(CIndex).Build22 = child.Attributes("treeTwo").Value
                    CharacterData(CIndex).Build23 = child.Attributes("treeThree").Value
                Else
                    CharacterData(CIndex).Build1name = child.Attributes("prim").Value
                    CharacterData(CIndex).Build1 = child.Attributes("treeOne").Value
                    CharacterData(CIndex).Build2 = child.Attributes("treeTwo").Value
                    CharacterData(CIndex).Build3 = child.Attributes("treeThree").Value
                End If
            Next
        Catch ex As Exception
        End Try

        '--- health & mana
        Try
            CharacterData(CIndex).Health = XMLnode.SelectSingleNode("characterTab/characterBars/health").Attributes("effective").Value
            If XMLnode.SelectSingleNode("characterTab/characterBars/secondBar").Attributes("type").Value = "m" Then
                CharacterData(CIndex).Mana = XMLnode.SelectSingleNode("characterTab/characterBars/secondBar").Attributes("effective").Value
            Else
                CharacterData(CIndex).Mana = 0
            End If
        Catch ex As Exception
        End Try

        '--- profession
        Try
            Dim skills As Xml.XmlNodeList = XMLnode.SelectNodes("characterTab/professions/skill")
            If skills IsNot Nothing Then
                If skills.Count >= 1 Then
                    CharacterData(CIndex).Prof1name = skills.Item(0).Attributes("name").Value
                    CharacterData(CIndex).Prof1value = skills.Item(0).Attributes("value").Value
                End If
                If skills.Count >= 2 Then
                    CharacterData(CIndex).Prof2name = skills.Item(1).Attributes("name").Value
                    CharacterData(CIndex).Prof2value = skills.Item(1).Attributes("value").Value
                End If
            End If
        Catch ex As Exception
        End Try

        '--- stats
        Try
            CharacterData(CIndex).Str = XMLnode.SelectSingleNode("characterTab/baseStats/strength").Attributes("effective").Value
            CharacterData(CIndex).Agi = XMLnode.SelectSingleNode("characterTab/baseStats/agility").Attributes("effective").Value
            CharacterData(CIndex).Sta = XMLnode.SelectSingleNode("characterTab/baseStats/stamina").Attributes("effective").Value
            CharacterData(CIndex).Int = XMLnode.SelectSingleNode("characterTab/baseStats/intellect").Attributes("effective").Value
            CharacterData(CIndex).Spi = XMLnode.SelectSingleNode("characterTab/baseStats/spirit").Attributes("effective").Value
        Catch ex As Exception
        End Try

        '--- spell 
        Try
            Dim spell(5) As Integer
            spell(0) = XMLnode.SelectSingleNode("characterTab/spell/bonusDamage/arcane").Attributes("value").Value
            spell(1) = XMLnode.SelectSingleNode("characterTab/spell/bonusDamage/fire").Attributes("value").Value
            spell(2) = XMLnode.SelectSingleNode("characterTab/spell/bonusDamage/frost").Attributes("value").Value
            spell(3) = XMLnode.SelectSingleNode("characterTab/spell/bonusDamage/holy").Attributes("value").Value
            spell(4) = XMLnode.SelectSingleNode("characterTab/spell/bonusDamage/nature").Attributes("value").Value
            spell(5) = XMLnode.SelectSingleNode("characterTab/spell/bonusDamage/shadow").Attributes("value").Value
            Array.Sort(spell)

            CharacterData(CIndex).SpellPower = spell(5)
        Catch ex As Exception
        End Try

        Try
            CharacterData(CIndex).SpellHit = XMLnode.SelectSingleNode("characterTab/spell/hitRating").Attributes("value").Value
            CharacterData(CIndex).SpellCrit = XMLnode.SelectSingleNode("characterTab/spell/critChance").Attributes("rating").Value
            CharacterData(CIndex).SpellHaste = XMLnode.SelectSingleNode("characterTab/spell/hasteRating").Attributes("hasteRating").Value
        Catch ex As Exception
        End Try

        Try
            CharacterData(CIndex).HealPower = XMLnode.SelectSingleNode("characterTab/spell/bonusHealing").Attributes("value").Value
            CharacterData(CIndex).ManaRegen = XMLnode.SelectSingleNode("characterTab/spell/manaRegen").Attributes("casting").Value
            CharacterData(CIndex).ManaRegRest = XMLnode.SelectSingleNode("characterTab/spell/manaRegen").Attributes("notCasting").Value
        Catch ex As Exception
        End Try

        '--- melee
        Try
            CharacterData(CIndex).MeleePower = XMLnode.SelectSingleNode("characterTab/melee/power").Attributes("effective").Value
            CharacterData(CIndex).MeleePenet = XMLnode.SelectSingleNode("characterTab/melee/hitRating").Attributes("penetration").Value
            CharacterData(CIndex).MeleeHit = XMLnode.SelectSingleNode("characterTab/melee/hitRating").Attributes("value").Value
            CharacterData(CIndex).MeleeCrit = XMLnode.SelectSingleNode("characterTab/melee/critChance").Attributes("rating").Value
            CharacterData(CIndex).MeleeDpsMH = XMLnode.SelectSingleNode("characterTab/melee/mainHandDamage").Attributes("dps").Value
            CharacterData(CIndex).MeleeDpsOH = XMLnode.SelectSingleNode("characterTab/melee/offHandDamage").Attributes("dps").Value
            CharacterData(CIndex).MeleeWSpeedMH = XMLnode.SelectSingleNode("characterTab/melee/mainHandDamage").Attributes("speed").Value
            CharacterData(CIndex).MeleeWSpeedOH = XMLnode.SelectSingleNode("characterTab/melee/offHandDamage").Attributes("speed").Value
            CharacterData(CIndex).MeleeHasteMH = XMLnode.SelectSingleNode("characterTab/melee/mainHandSpeed").Attributes("hasteRating").Value
            CharacterData(CIndex).MeleeHasteOH = XMLnode.SelectSingleNode("characterTab/melee/offHandSpeed").Attributes("hasteRating").Value
        Catch ex As Exception
        End Try

        '--- ranged
        Try
            CharacterData(CIndex).RangedPower = XMLnode.SelectSingleNode("characterTab/ranged/power").Attributes("effective").Value
            CharacterData(CIndex).RangedPenet = XMLnode.SelectSingleNode("characterTab/ranged/hitRating").Attributes("penetration").Value
            CharacterData(CIndex).RangedHit = XMLnode.SelectSingleNode("characterTab/ranged/hitRating").Attributes("value").Value
            CharacterData(CIndex).RangedCrit = XMLnode.SelectSingleNode("characterTab/ranged/critChance").Attributes("rating").Value
            CharacterData(CIndex).RangedDps = XMLnode.SelectSingleNode("characterTab/ranged/damage").Attributes("dps").Value
            CharacterData(CIndex).RangedWSpeed = XMLnode.SelectSingleNode("characterTab/ranged/damage").Attributes("speed").Value
            CharacterData(CIndex).RangedHaste = XMLnode.SelectSingleNode("characterTab/ranged/speed").Attributes("hasteRating").Value
        Catch ex As Exception
        End Try

        '--- defense
        Try
            CharacterData(CIndex).Armor = XMLnode.SelectSingleNode("characterTab/defenses/armor").Attributes("effective").Value
            CharacterData(CIndex).Defense = XMLnode.SelectSingleNode("characterTab/defenses/defense").Attributes("rating").Value
            CharacterData(CIndex).Dodge = XMLnode.SelectSingleNode("characterTab/defenses/dodge").Attributes("rating").Value
            CharacterData(CIndex).Parry = XMLnode.SelectSingleNode("characterTab/defenses/parry").Attributes("rating").Value
            CharacterData(CIndex).Block = XMLnode.SelectSingleNode("characterTab/defenses/block").Attributes("rating").Value
            CharacterData(CIndex).Resilience = XMLnode.SelectSingleNode("characterTab/defenses/resilience").Attributes("value").Value
        Catch ex As Exception
        End Try

        '===== Items =====
        Dim ItemNode As Xml.XmlElement
        If XMLnode.SelectNodes("characterTab/items/item") IsNot Nothing Then
            ReDim CharacterData(CIndex).items(19)
            ReDim CharacterData(CIndex).ench(19)
        End If

        Dim gct As Long = 0
        For Each ItemNode In XMLnode.SelectNodes("characterTab/items/item")
            Dim slot As Integer
            slot = ItemNode.Attributes("slot").Value
            If -1 <= slot And slot <= 18 Then
                CharacterData(CIndex).items(slot + 1) = ItemDB.GetItemInfo(ItemNode.Attributes("id").Value).ID
                CharacterData(CIndex).ench(slot + 1) = ItemNode.Attributes("permanentenchant").Value
            Else
                MsgBox("item error, slot=" & slot)
            End If
            Dim g(2) As Integer

            Try
                g(0) = ItemDB.GetItemInfo(ItemNode.Attributes("gem0Id").Value).ID
                g(1) = ItemDB.GetItemInfo(ItemNode.Attributes("gem1Id").Value).ID
                g(2) = ItemDB.GetItemInfo(ItemNode.Attributes("gem2Id").Value).ID
            Catch ex As Exception

            End Try
            Dim i As Integer
            For i = 0 To 2
                If g(i) > 0 Then
                    If CharacterData(CIndex).gems Is Nothing Then
                        ReDim CharacterData(CIndex).gems(0)
                    Else
                        ReDim Preserve CharacterData(CIndex).gems(gct)
                    End If

                    CharacterData(CIndex).gems(gct) = g(i)
                    gct += 1
                End If
            Next

            Dim iLevel As Integer = 0
            Dim iLvAverage As Single = 0
            Dim two_handed As Integer
            For i = 0 To CharacterData(CIndex).items.Length - 1
                two_handed = 1
                '--- two hands
                If i = 16 And CharacterData(CIndex).items(17) = 0 Then
                    Select Case ItemDB.GetItemInfo(CharacterData(CIndex).items(i)).Type
                        Case "Fishing Poles"
                            two_handed = 2
                        Case "Polearms"
                            two_handed = 2
                        Case "Two-Handed Axes"
                            two_handed = 2
                        Case "Two-Handed Maces"
                            two_handed = 2
                        Case "Two-Handed Swords"
                            two_handed = 2
                        Case "Staves"
                            two_handed = 2
                        Case Else
                            two_handed = 1
                    End Select
                End If
                Select Case i
                    Case 0  'Bullets
                    Case 4  'Shirt
                    Case 19 'Tabard
                    Case Else
                        Dim ilv As Integer = ItemDB.GetItemInfo(CharacterData(CIndex).items(i)).Lvl
                        Select Case ItemDB.GetItemInfo(CharacterData(CIndex).items(i)).Qlty
                            Case 0 ' gray 
                                '
                            Case 1 ' white
                                '
                            Case 2 ' green
                                If ilv >= 13 Then
                                    iLevel += Math.Round((ilv - 8) / 2 * 1.2 + 26, 0) * two_handed
                                End If
                            Case 3 ' blue
                                If ilv >= 26 Then
                                    iLevel += Math.Round((ilv - 0.75) / 1.8 * 1.2 + 26, 0) * two_handed
                                End If
                            Case Else ' purple, orange
                                iLevel += ilv * two_handed
                        End Select
                End Select
            Next
            iLvAverage = Math.Round(iLevel / 17, 1)

            CharacterData(CIndex).iLvTotal = iLevel
            CharacterData(CIndex).iLvAve = iLvAverage
        Next

        '===== talents =====
        Try
            XMLnode = Armory.GetArmoryCharacter(CharacterData(CIndex).Realm, CharacterData(CIndex).Character, XMLdoc, AccessArmory.UrlCharactersInfo.UrlChTalents)
        Catch ex As Exception
            Return CharacterData(CIndex)
        End Try
        If XMLnode Is Nothing Then
            Return CharacterData(CIndex)
        End If

        Try
            CharacterData(CIndex).ErrCode = XMLnode.Attributes("errCode").Value
        Catch ex As Exception
        End Try

        Dim glnode As Xml.XmlElement = Nothing
        Dim gc As Integer = 0

        Dim GlyphDB As New WowCrawler.GlyphDB
        For Each child In XMLnode.SelectNodes("talents/talentGroup")

            If child.Attributes("active") Is Nothing Then
                CharacterData(CIndex).Talent2 = child.SelectSingleNode("talentSpec").Attributes("value").Value

                gc = 0
                For Each glnode In child.SelectNodes("glyphs/glyph")
                    ReDim Preserve CharacterData(CIndex).Glyph2(gc)
                    Try
                        CharacterData(CIndex).Glyph2(gc) = glnode.Attributes("id").Value
                        GlyphDB.AddGlyphInfo(glnode.Attributes("id").Value, glnode.Attributes("type").Value, glnode.Attributes("name").Value)
                    Catch ex As Exception
                    End Try
                    gc += 1
                Next
            ElseIf child.Attributes("active").Value = 0 Then
                CharacterData(CIndex).Talent2 = child.SelectSingleNode("talentSpec").Attributes("value").Value

                gc = 0
                For Each glnode In child.SelectNodes("glyphs/glyph")
                    ReDim Preserve CharacterData(CIndex).Glyph2(gc)
                    Try
                        CharacterData(CIndex).Glyph2(gc) = glnode.Attributes("id").Value
                        GlyphDB.AddGlyphInfo(glnode.Attributes("id").Value, glnode.Attributes("type").Value, glnode.Attributes("name").Value)
                    Catch ex As Exception
                    End Try
                    gc += 1
                Next
            Else
                CharacterData(CIndex).Talent = child.SelectSingleNode("talentSpec").Attributes("value").Value

                gc = 0
                For Each glnode In child.SelectNodes("glyphs/glyph")
                    ReDim Preserve CharacterData(CIndex).Glyph(gc)
                    Try
                        CharacterData(CIndex).Glyph(gc) = glnode.Attributes("id").Value
                        GlyphDB.AddGlyphInfo(glnode.Attributes("id").Value, glnode.Attributes("type").Value, glnode.Attributes("name").Value)
                    Catch ex As Exception
                    End Try
                    gc += 1
                Next
            End If
        Next
        GlyphDB.StoreGlyphDB()

        '===== achievements =====
        'Try
        '    XMLnode = Armory.GetArmoryCharacter(CharacterData(CIndex).Realm, CharacterData(CIndex).Character, XMLdoc, AccessArmory.UrlCharactersInfo.UrlAchievements, AccessArmory.AchievementsCategories.General)
        '    XMLdoc.Save(My.Computer.FileSystem.CombinePath(DataPath, "LastArmoryAchievementBase.xml"))
        'Catch ex As Exception
        'End Try
        'If XMLnode Is Nothing Then
        '    Return CharacterData(CIndex)
        'End If
        Try
            XMLnode = Nothing
            XMLnode = Armory.GetArmoryCharacter(CharacterData(CIndex).Realm, CharacterData(CIndex).Character, XMLdoc, AccessArmory.UrlCharactersInfo.UrlChAchievements, AccessArmory.AchievementsCategories.DungeonsAndRaids)
        Catch ex As Exception
        End Try
        If XMLnode IsNot Nothing Then
            AchDB.SetAchievementId(XMLnode.OuterXml, CharacterData(CIndex).Achievements)
        End If

        Try
            XMLnode = Nothing
            XMLnode = Armory.GetArmoryCharacter(CharacterData(CIndex).Realm, CharacterData(CIndex).Character, XMLdoc, AccessArmory.UrlCharactersInfo.UrlChAchievements, AccessArmory.AchievementsCategories.PlayerVsPlayer)
        Catch ex As Exception
        End Try
        If XMLnode IsNot Nothing Then
            AchDB.SetAchievementId(XMLnode.OuterXml, CharacterData(CIndex).Achievements)
        End If


        '==== Auto Save ====
        ArmoryAccessCounter += 1
        If ArmoryAccessCounter Mod 10 = 0 Then
            SaveArmoryData()
        End If

        Return CharacterData(CIndex)
    End Function

    Public Sub SetRejectCharacter(ByVal Rejected As Boolean, ByVal CharaName As String, ByVal AkaName As String)
        Dim i As Integer
        If CharaName = "" Then
            Exit Sub
        End If
        If CharaName = AkaName Then
            AkaName = ""
        End If

        For i = 0 To CharacterData.Length - 1
            If CharacterData(i).Character = CharaName Then
                CharacterData(i).Rejected = Rejected
                If Rejected Then
                    CharacterData(i).AkaChara = AkaName
                    CharacterData(i).Guild = ""
                Else
                    CharacterData(i).AkaChara = ""
                End If
            End If
        Next
    End Sub
End Class


Public Class CompareCharacters
    Implements IComparer

    Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
        Dim c1 As CharactersInfo.Characters = CType(x, CharactersInfo.Characters)
        Dim c2 As CharactersInfo.Characters = CType(y, CharactersInfo.Characters)

        Dim d1 As String = c1.Region & " " & c1.Realm & " " & c1.Guild & " " & c1.Character
        Dim d2 As String = c2.Region & " " & c2.Realm & " " & c2.Guild & " " & c2.Character

        If d1 < d2 Then
            Return -1
        ElseIf d1 > d2 Then
            Return 1
        End If

        Return 0
    End Function
End Class




